﻿using System;
using System.Windows.Controls;
using System.Windows.Navigation;
using CARE.Web.Services;
using CARE.Web.db;
using System.Windows.Ria.Data;
using GraphInformation;
using System.Collections.Generic;
using GraphLayout.GraphRepresentation;
using System.Windows.Shapes;
using System.Windows.Media;
using System.Windows;

namespace CARE
{
    public partial class DiseaseModel : Page
    {
        GraphProvider gp = new GraphProvider();
        Dictionary<int, NodeItem> map = new Dictionary<int, NodeItem>();
        private Brush normalBrush = new SolidColorBrush(Colors.Black);

        public DiseaseModel()
        {
            InitializeComponent();       
        }

        private void RemoveChosenModel_Click(object sender, RoutedEventArgs e)
        {
            ((List<Disease>) DiseaseDataSource.Data).Remove(((Disease) Diseases.SelectedItem));
        }

        private void SaveDescription_Click(object sender, RoutedEventArgs e)
        {
            DiseaseDataSource.SubmitChanges();
        }

        private void Diseases_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {        
            map.Clear();
            rootCanvas.Children.Clear();
            String grapgML = ((Disease)Diseases.SelectedItem).data.ToString();
            gp.Graphs.Clear();
            var a =gp.Load(gp.GetDiseaseModelGraphQuery(grapgML));
            a.Completed += new EventHandler(GetDiseaseModelGraphQuery_Completed);            
        }

        void GetDiseaseModelGraphQuery_Completed(object sender, EventArgs e)
        {            
            Dictionary<Guid, NodeItem> map = new Dictionary<Guid, NodeItem>();
            foreach (GraphElement node in gp.Graphs[0].Vertices)
            {
                double x = rootCanvas.Width / 2;
                double y = rootCanvas.Height / 2;
                string name = string.Empty;
                string color = string.Empty;
                foreach (PairKeyValue item in node.Keys)
                    if (item.Key == "stateName")
                        name = item.Value;
                    else if (item.Key == "nodeColor")
                        color = item.Value;
                    else if (item.Key == "nodeX" && item.Value != null)
                        x = double.Parse(item.Value);
                    else if (item.Key == "nodeY" && item.Value != null)
                        y = double.Parse(item.Value);
                var elem = CreateNode(map, node.ID, x, y, name, color);
                //elem.Graph = graph;
            }

            foreach (GraphEdge edge in gp.Graphs[0].Edges)
            {
                double startX = (double)map[edge.Source].GetValue(Canvas.LeftProperty) + map[edge.Source].Width / 2;
                double startY = (double)map[edge.Source].GetValue(Canvas.TopProperty) + map[edge.Source].Height / 2;
                double endX = (double)map[edge.Target].GetValue(Canvas.LeftProperty) + map[edge.Source].Width / 2;
                double endY = (double)map[edge.Target].GetValue(Canvas.TopProperty) + map[edge.Source].Height / 2;

                CreateEdge(map[edge.Source], map[edge.Target], startX, startY, endX, endY);
            }
        }

        NodeItem CreateNode(Dictionary<Guid, NodeItem> map, Guid id, double x, double y, string name, string color)
        {
            Canvas RectWithTitle = CreateRectangleWithTitle(name, FromKnownColor(color));

            RectWithTitle.SetValue(Canvas.LeftProperty, 2.5);
            RectWithTitle.SetValue(Canvas.TopProperty, 2.5);

            NodeItem element = new NodeItem()
            {
                Width = RectWithTitle.Width,
                Height = RectWithTitle.Height

            };
            element.X = (float)x;
            element.Y = (float)y;
            element.SetValue(Canvas.LeftProperty, x);
            element.SetValue(Canvas.TopProperty, y);

            element.Children.Add(RectWithTitle);


            map.Add(id, element);
            rootCanvas.Children.Add(element);

            return element;
        }

        void CreateEdge(NodeItem source, NodeItem target, double startX, double startY, double endX, double endY)
        {
            if (startX - source.Width / 2 > endX + target.Width / 2)
            {
                startX -= source.Width / 2;
                endX += target.Width / 2;
                if (startY - source.Height / 2 > endY + target.Height / 2)
                {
                    startY -= source.Height / 2;
                    endY += target.Height / 2;
                }
                else if (startY + source.Height / 2 > endY - target.Height / 2)
                {
                    // nothing
                }
                else
                {
                    startY += source.Height / 2;
                    endY -= target.Height / 2;
                }
            }
            else if (startX + source.Width / 2 > endX - target.Width / 2)
            {
                if (startY - source.Height / 2 > endY + target.Height / 2)
                {
                    startY -= source.Height / 2;
                    endY += target.Height / 2;
                }
                else if (startY + source.Height / 2 > endY - target.Height / 2)
                {
                    // nothing
                }
                else
                {
                    startY += source.Height / 2;
                    endY -= target.Height / 2;
                }
            }
            else
            {
                startX += source.Width / 2;
                endX -= target.Width / 2;
                if (startY - source.Height / 2 > endY + target.Height / 2)
                {
                    startY -= source.Height / 2;
                    endY += target.Height / 2;
                }
                else if (startY + source.Height / 2 > endY - target.Height / 2)
                {
                    // nothing
                }
                else
                {
                    startY += source.Height / 2;
                    endY -= target.Height / 2;
                }
            }

            var line = new Line
            {
                X1 = startX,
                Y1 = startY,
                X2 = endX,
                Y2 = endY,
                Stroke = new SolidColorBrush(Colors.Black),
                StrokeThickness = 3
            };

            Polygon lineArrow = new Polygon();
            lineArrow.Points = new PointCollection();
            lineArrow.Fill = new SolidColorBrush(Colors.Black);
            Point l1;
            Point l2;

            // Getting Arrow
            RotateTransform rot1 = new RotateTransform();
            rot1.Angle = 45.0;
            rot1.CenterX = endX;
            rot1.CenterY = endY;

            RotateTransform rot2 = new RotateTransform();
            rot2.Angle = -45.0;
            rot2.CenterX = endX;
            rot2.CenterY = endY;

            double px = startX - endX;
            double py = startY - endY;
            double d = Math.Sqrt(px * px + py * py);
            px /= d;
            py /= d;
            l1 = rot1.Transform(new Point(endX + 15 * px, endY + 15 * py));
            l2 = rot2.Transform(new Point(endX + 15 * px, endY + 15 * py));

            //TODO: arrow
            lineArrow.Points.Add(new Point(endX, endY));
            lineArrow.Points.Add(new Point(l1.X, l1.Y));
            lineArrow.Points.Add(new Point(l2.X, l2.Y));

            EdgeItem lineCanvas = new EdgeItem()
            {
                Height = line.Height,
                Width = line.Width
            };

            lineCanvas.VisualLine = line;

            lineCanvas.Children.Add(line);
            lineCanvas.Children.Add(lineArrow);
            rootCanvas.Children.Add(lineCanvas);
        }

        public static Color FromKnownColor(string colorName)
        {
            Line line = (Line)System.Windows.Markup.XamlReader.Load("<Line xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" Fill=\"" + colorName + "\" />");
            return (Color)line.Fill.GetValue(SolidColorBrush.ColorProperty);
        }

        public Canvas CreateRectangleWithTitle(String name, Color color)
        {
            LinearGradientBrush myHorizontalGradient = GetGradient(color);
            Brush projBrush = myHorizontalGradient;

            Brush textColor = new SolidColorBrush(Colors.Black);
            TextBlock title = new TextBlock()
            {
                Foreground = textColor,
                Text = name,
                FontSize = 12
            };

            double Height = 25d;
            double Width = (title.ActualWidth + 4) < Height ? Height : title.ActualWidth + 4;
            Width += 4;

            Canvas RectWithTitle = new Canvas()
            {
                Width = Width,
                Height = Height
            };

            Rectangle nodeBkg = new Rectangle()
            {
                Width = Width,
                Height = Height,
                Fill = projBrush,
                Stroke = normalBrush
            };

            nodeBkg.RadiusX = 10;
            nodeBkg.RadiusY = 10;

            RectWithTitle.Children.Add(nodeBkg);
            RectWithTitle.Children.Add(title);

            double left = (nodeBkg.Width - title.ActualWidth) / 2;
            double top = (nodeBkg.Height - title.ActualHeight) / 2;
            title.SetValue(Canvas.LeftProperty, left);
            title.SetValue(Canvas.TopProperty, top);

            return RectWithTitle;
        }

        private static LinearGradientBrush GetGradient(Color second)
        {
            GradientStopCollection GradientStops = new GradientStopCollection();
            LinearGradientBrush myHorizontalGradient = new LinearGradientBrush();
            myHorizontalGradient.StartPoint = new Point(0.5, 0);
            myHorizontalGradient.EndPoint = new Point(0.5, 1);
            myHorizontalGradient.GradientStops.Add(new GradientStop()
            {
                Color = second,
                Offset = 1.0
            });
            myHorizontalGradient.GradientStops.Add(new GradientStop()
            {
                Color = Colors.White,
                Offset = 0.1
            });
            return myHorizontalGradient;
        }

        private void LinkCreate_Click(object sender, RoutedEventArgs e)
        {
            new CARE.Views.ModelEditor().Show();
        }

        private void LinkEditModel_Click(object sender, RoutedEventArgs e)
        {

        }
    }
}
